#include <stdlib.h>
#include <Time.h>
#include <QDebug>

#include "Controller.h"
#include "Cell.h"
#include "PriorityQueue.h"

#include "Field.h"
#include "Mob.h"
#include "BlackHole.h"
#include "Gangster.h"
#include "Wall.h"
#include "Bullet.h"
#include "Object.h"

#include "RoamingGangster.h"
#include "FollowerGangster.h"
#include "WaypointGangster.h"

Controller* randController() {
    int i = rand() % 3;
    switch( i ) {
        case( 0 ): return new RoamingGangster();
        case( 1 ): return new FollowerGangster();
        case( 2 ): return new WaypointGangster();
        default:   return new RoamingGangster();
    }
}

Cell Controller::getPath() {
    if( path.size() ) {
        Cell c = path.back();
        path.pop_back();
        return c;
    }
    return Cell( -1, -1, 0, 0, 0 );
}

bool Controller::hasPath() {
    if( path.size() ) return true;
    else return false;
}

bool Controller::evade() {
    Direction d, e, f;
    d = mob->getField()->dangerInSight( mob );
    e = d;
    f = invertDirection( e );
    if( d != NONE && hasPath() ) {
        Direction g = cellToDirection( path.back(), mob );
        if( g != NONE && g != e && g != f ) {
            if( mob->getField()->move( g, 1, mob ) ) return true;
        }
    }
    if( d != NONE ) {
        d = NORTH;
        for( ; d < NONE; ++d ) {
            if( d == e || d == f ) {
                continue;
            }
            if( mob->getField()->move( d, 1 , mob ) ) {
                return true;
            }
        }
    }
    mob->getField()->shift( mob );
    return false;
}

void Controller::findPath( int x1, int y1, int x2, int y2 ) {
    vector<Cell> openList, closedList;
    Field* field = mob->getField();
    int x = x1, y = y1, time = 0, x_, y_;
    Object* o;
    bool pathFound = false;
    Cell null = Cell( -1, -1, 0, 0, 0 );

    closedList.push_back( Cell(x1, y1, time, x2, y2 ) );
    for( int j = 0; !pathFound && j < SEARCHDEPTH; j++ ) {
        boost::shared_ptr<Cell> q( new Cell( closedList.back() ) );
        x = q->getX();
        y = q->getY();

        for( Direction i = NORTH; i < NONE; ++i ) {
            o = field->objectAt( i, 1, x, y );
            if( o ) {
                x_ = o->getX();
                y_ = o->getY();
            } else {
                x_ = field->objectAtX( i, 1, x );
                y_ = field->objectAtY( i, 1, y );
            }
            Cell c( -1, -1, 0, 0, 0 );
            if( isPassable(o) && !isInList( x_, y_, closedList ) ) {
                c = getFromList( x_, y_, openList );
                if( c == null ) {
                    openList.push_back( Cell( x_, y_, time, q, x2, y2 ) );
                } else {
                    if( c.getG() < Cell( x_, y_, time, q, x2, y2  ).getG() ) {
                        c.setPath( q );
                    }
                }
            }
        }

        Heapsort<Cell>( openList, openList.size() );
        if( openList.size() ) {
            closedList.push_back( openList.back() );
            openList.pop_back();
        }

        if( closedList.back().getX() == x2 && closedList.back().getY() == y2 ) {
            pathFound = true;
        }
    }
    if( closedList.size() ) {
        list<Cell> list;
        for( Cell d = closedList.back(); d.getPath() != 0 && d.isNull();
             d = *( d.getPath() )  ) {
            list.push_back( d );
        }
        path = list;
    }
}
